package im_server

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gomodule/redigo/redis"
	"github.com/gorilla/websocket"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"pim/pkg/codes"
	"pim/pkg/models"
	"pim/pkg/promePkg"
	"pim/pkg/tools"
)

func (c *ClientConn) ProcMessage(message []byte) {
	version := message[0]
	modType := uint16(message[1])<<8 |
		uint16(message[2])

	subType := uint16(message[3])<<8 |
		uint16(message[4])

	uniqueID := int64(message[5])<<56 |
		int64(message[6])<<48 |
		int64(message[7])<<40 |
		int64(message[8])<<32 |
		int64(message[9])<<24 |
		int64(message[10])<<16 |
		int64(message[11])<<8 |
		int64(message[12])

	data := message[13:]

	var respSubType uint16
	var respData []byte
	var err error

	promePkg.PromeInc(promePkg.ApiRequestCounter)

	if version == 1 {
		switch modType {

		case codes.UserMod:
			respSubType, respData, err = c.ProcToUserMod(subType, uniqueID, data)
		case codes.MsgMod:
			respSubType, respData, err = c.ProcToMsgMod(subType, uniqueID, data)
		case codes.GroupMod:
			respSubType, respData, err = c.ProcToGroupMod(subType, uniqueID, data)

		case codes.ConversationMod:
			respSubType, respData, err = c.ProcToConversiontionMod(subType, uniqueID, data)

		}

		var respOutput []byte
		if err != nil {
			// 返回错误信息

			errMsg := err.Error()
			respOutput = make([]byte, len(errMsg)+13)
			//
			respOutput[0] = 1
			respOutput[1] = 0
			respOutput[2] = 0
			respOutput[3] = 0
			respOutput[4] = 0
			respOutput[5] = message[5]
			respOutput[6] = message[6]
			respOutput[7] = message[7]
			respOutput[8] = message[8]
			respOutput[9] = message[9]
			respOutput[10] = message[10]
			respOutput[11] = message[11]
			respOutput[12] = message[12]
			copy(respOutput[13:], errMsg)
			promePkg.PromeInc(promePkg.ApiRequestFailedCounter)

		} else {
			respOutput = make([]byte, len(respData)+13)

			respOutput[0] = 1
			respOutput[1] = message[1]
			respOutput[2] = message[2]
			respOutput[3] = byte(respSubType >> 8)
			respOutput[4] = byte(respSubType)
			respOutput[5] = message[5]
			respOutput[6] = message[6]
			respOutput[7] = message[7]
			respOutput[8] = message[8]
			respOutput[9] = message[9]
			respOutput[10] = message[10]
			respOutput[11] = message[11]
			respOutput[12] = message[12]

			copy(respOutput[13:], respData)
			promePkg.PromeInc(promePkg.ApiRequestSuccessCounter)

		}
		// 拼接回包

		err = c.WriteMessage(websocket.BinaryMessage, respOutput)
		if err != nil {
			// TODO
		}

	} else {
		// 协议不支持
	}

}

func (c *ClientConn) ProcToUserMod(subType uint16, uniqueID int64, data []byte) (respSubType uint16, respData []byte, err error) {

	switch subType {
	case codes.UserModGetMeReq:
		respSubType = codes.UserModGetMeResp
		// 不需要参数直接读取
		respObj, errApi := c.UserModGetME()
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)
		return
	case codes.UserModGetUserByIdReq:
		respSubType = codes.UserModGetUserByIdResp
		var req models.GetUserByIdReq
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}
		respObj, errApi := c.UserModGetUserByID(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)

		return
	case codes.UserModAddUserToContactReq:
		respSubType = codes.UserModAddUserToContactResp
		var req models.Contact
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}
		respObj, errApi := c.UserModAddUserToContact(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)

		return

	}

	return
}
func (c *ClientConn) ProcToConversiontionMod(subType uint16, uniqueID int64, data []byte) (respSubType uint16, respData []byte, err error) {
	switch subType {
	case codes.ConversationModGetListReq:
		respSubType = codes.ConversationModGetListResp
		var senderMsgReq models.LimitOffsetReq
		err = json.Unmarshal(data, &senderMsgReq)
		if err != nil {
			return
		}

		respObj, errApi := c.GetMyConversationList(&senderMsgReq)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)

		return

	}
	return
}

func ProcMessage(req interface{}, data []byte, resp interface{}, doApi func(req interface{}) (interface{}, error)) (err error) {
	err = json.Unmarshal(data, req)
	if err != nil {
		return
	}

	respObj, errApi := doApi(req)

	if errApi != nil {
		err = errApi
		return
	}
	respData, err := json.Marshal(respObj)

	resp = respData
	return
}

func (c *ClientConn) ProcToMsgMod(subType uint16, uniqueID int64, data []byte) (respSubType uint16, respData []byte, err error) {
	switch subType {
	case codes.MsgModSenderMsgReq:
		respSubType = codes.MsgModSenderMsgResp
		var senderMsgReq models.SenderMsgReq

		err = json.Unmarshal(data, &senderMsgReq)
		if err != nil {
			return
		}

		respObj, errApi := c.SenderMsgApi(&senderMsgReq)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)

		return

	case codes.MsgModCreateChatReq:
		respSubType = codes.MsgModCreateChatResp
		var req models.CreateChatReq
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}

		respObj, errApi := c.CreateChatApi(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)
		return
	case codes.MsgModSyncChatReq:
		respSubType = codes.MsgModSyncChatResp
		var req models.SyncChatMsgReq
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}

		respObj, errApi := c.SyncChatMsgApi(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)
	case codes.MsgModGetHistoryMsgReq:
		respSubType = codes.MsgModGetHistoryMsgResp
		var req models.GetHistoryMsgReq
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}

		respObj, errApi := c.GetHistoryMsgApi(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)
	case codes.MsgModCreateUploadTaskReq:
		respSubType = codes.MsgModCreateUploadTaskResp
		var req models.CreateUploadTaskReq
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}

		respObj, errApi := c.CreateUploadTaskApi(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)
	case codes.MsgModStopUploadTaskReq:
		respSubType = codes.MsgModStopUploadTaskResp
		var req models.StopUploadTaskReq
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}

		respObj, errApi := c.StopUploadTaskApi(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)
	case codes.MsgModSendUploadPackageReq:
		respSubType = codes.MsgModSendUploadPackageResp
		var req models.SendUploadPackageReq

		req.FileID = int64(data[0])<<24 |
			int64(data[1])<<16 |
			int64(data[2])<<8 |
			int64(data[3])

		req.Offset = int(data[4])<<24 |
			int(data[5])<<16 |
			int(data[6])<<8 |
			int(data[7])
		req.Limit = int(data[8])<<24 |
			int(data[9])<<16 |
			int(data[10])<<8 |
			int(data[11])

		if len(data) != req.Limit+12 {
			err = errors.New("数据包错误")
			return
		}

		req.Body = data[12 : req.Limit+12]

		respObj, errApi := c.SendUploadPackageApi(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)
	case codes.MsgModContinueUploadPackageReq:
		respSubType = codes.MsgModContinueUploadPackageResp
		var req models.ContinueUploadPackageReq
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}

		respObj, errApi := c.ContinueUploadPackageApi(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)
	case codes.MsgModPauseUploadPackageReq:
		respSubType = codes.MsgModPauseUploadPackageResp
		var req models.PauseUploadPackageReq
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}

		respObj, errApi := c.PauseUploadPackageReqApi(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)
	case codes.MsgModDoneUploadPackageReq:
		respSubType = codes.MsgModDoneUploadPackageResp
		var req models.DoneUploadPackageReq
		err = json.Unmarshal(data, &req)
		if err != nil {
			return
		}

		respObj, errApi := c.DoneUploadPackageApi(&req)
		if errApi != nil {
			err = errApi
			return
		}
		respData, err = json.Marshal(respObj)

	}
	return
}

func (c *ClientConn) GenMsgID() tools.ID {
	return c.svr.msgNode.Generate()
}

func (c *ClientConn) KickDevice() {
	packAge := tools.ProtocolPackage{
		Version: 1,
		ModType: codes.EventMod,
		SubType: codes.EventModKickDevice,
	}

	c.WriteMessage(websocket.BinaryMessage, packAge.Bytes())
	c.IsClose = true
	c.Close()

}

func (c *ClientConn) GetMyConversationList(req *models.LimitOffsetReq) (resp *models.ConversionItem, err error) {
	// 生成假数据

	// 从redis 查询会话列表

	redisConn := c.svr.redisPool.Get()
	defer func() {
		redisConn.Close()
	}()

	rkeyFind := fmt.Sprintf("%s:%X:*", codes.RedisUserChatListPrefix, c.UserID)

	rkeyList, err := redis.Strings(redisConn.Do("KEYS", rkeyFind))
	if err != nil {
		c.logger.Debug("查找redis 信息失败", zap.Error(err))
		err = errors.New("not found conversions")
		return
	}

	// 查询现有的会话
	resp = new(models.ConversionItem)
	for index, rkey := range rkeyList {

		if index == req.Limit {
			//break
		}

		tmp := &models.ChatInfoDataType{}

		getRedisAll, err := redis.Values(redisConn.Do("HGETALL", rkey))
		if err != nil {
			continue
		}

		err = redis.ScanStruct(getRedisAll, tmp)

		if err != nil {
			continue
		}

		// 成功
		resp.ChatList = append(resp.ChatList, tmp)
	}

	resp.Count = len(rkeyList)

	// 返回客户端

	//resp.Count = 2
	//chatInfo1 := &models.ChatInfoDataType{
	//	ChatInfo: models.ChatInfo{
	//		ChatID:    1,
	//		ChatName:  "ID1",
	//		ChatTitle: "ID1",
	//	},
	//
	//	LastMsgID:      2,
	//	LastUpdateTime: time.Now().UnixMilli(),
	//}
	//
	//chatInfo2 := &models.ChatInfoDataType{
	//	ChatInfo: models.ChatInfo{
	//		ChatID:    2,
	//		ChatName:  "ID2",
	//		ChatTitle: "ID2",
	//	},
	//	LastMsgID:      2,
	//	LastUpdateTime: time.Now().UnixMilli(),
	//}
	//
	//resp.ChatList = append(resp.ChatList, chatInfo1, chatInfo2)

	return
}

func (c *ClientConn) DoInitUserContext() {
	// 执行用户的初始化信息
	// 读取会话列表

	// 直接读取会话列表即可
	// 推送自己的用户id

	db := c.svr.db
	//c.doPushMyUserInfo(db)
	c.doPushConversions(db)

}

func (c *ClientConn) doPushConversions(db *gorm.DB) {
	// 读取会话列表

	//var chatList = []*models.ChatInfoDataType{}

	var chatList = make(map[int64]*models.ChatInfoDataType)
	//rest := db.Model(&models.ChatInfoDataType{})

	rest := db.Raw("select  chat.chat_id as chat_id  , chat.my_user_id as my_user_id,chat.chat_name as chat_name ,chat.chat_title as chat_title,"+
		"tmp.msg_id as last_msg_id,tmp.created_at as last_update_time "+
		" from chat_infos chat LEFT JOIN "+
		"(select all_msg.* from single_messages all_msg where all_msg.msg_id in (select MAX(msg.msg_id) "+
		"from single_messages msg where  msg.sender = ? or msg.chat_id =?  GROUP BY msg.sender ,msg.chat_id ) ORDER BY all_msg.created_at "+
		") tmp on (tmp.chat_id = chat.chat_id and tmp.sender = chat.my_user_id) or (tmp.chat_id = chat.my_user_id and tmp.sender = chat.chat_id) WHERE my_user_id = ?", c.UserID, c.UserID, c.UserID)

	//rest.Rows()
	rows, err := rest.Rows()

	if err != nil {
		return
	}

	for rows.Next() {
		item := &models.ChatInfoDataType{}
		var lastMsgID interface{}
		var lastUpdateTime interface{}
		err = rows.Scan(&item.ChatID, &item.MyUserID, &item.ChatName, &item.ChatTitle, &lastMsgID, &lastUpdateTime)
		if err != nil {
			continue
		}

		if lastMsgID != nil {
			item.LastMsgID = lastMsgID.(int64)
		}
		if lastUpdateTime != nil {
			item.LastUpdateTime = lastUpdateTime.(int64)
		}
		//判断是否存在会话
		oldChat, isok := chatList[item.ChatID]
		if !isok {
			chatList[item.ChatID] = item
			continue
		}
		// 判断那个消息最新
		if oldChat.LastMsgID < item.LastMsgID {
			// 新消息更新 则使用新的代替
			chatList[item.ChatID] = item
		}

		// 否则不处理
		//chatList = append(chatList, item)
	}

	c.logger.Debug("chat list", zap.Any("chat ", chatList))
	// 推送会话列表

	var lastMsgItem []int64

	// 查询
	for _, chatInfo := range chatList {
		//jsonBuffer , _ := json.Marshal(chatInfo)

		_ = c.PushEventToClient(codes.EventMod, codes.EventModNewChatInfo, chatInfo)
		// 同时推送最新的消息到客户端
		if chatInfo.LastMsgID > 0 {
			lastMsgItem = append(lastMsgItem, chatInfo.LastMsgID)
		}
	}

	// 查询需要推送的消息到客户端

	var willPushLastMsgItem []*models.SingleMessage

	err = db.Model(&models.SingleMessage{}).Where("msg_id in ? ", lastMsgItem).Find(&willPushLastMsgItem).Error
	if err != nil {
		return
	}

	for _, message := range willPushLastMsgItem {
		pushBody := DBMessageToClientMessage(c.UserID, message)

		_ = c.PushEventToClient(codes.EventMod, codes.EventModNewMessage, pushBody)
	}

}
func (c *ClientConn) doPushMyUserInfo(db *gorm.DB) {

	var myUserInfo models.UserInfoViewer

	err := db.Model(&models.UserInfoViewer{}).Where(&models.UserInfoViewer{
		UserID: c.UserID,
	}).Find(&myUserInfo).Error

	if err != nil {
		c.logger.Debug("读取我自己的用户信息失败", zap.Error(err))
		return
	}

	jsonUserInfo, _ := json.Marshal(&myUserInfo)
	// 推送数据

	uinfoPackage := tools.NewProtocolPackage(codes.EventMod, codes.EventModUpdateUserInfo, 0, jsonUserInfo)

	outputBytes := uinfoPackage.Bytes()
	err = c.WriteMessage(websocket.BinaryMessage, outputBytes)
	if err != nil {
		c.logger.Debug("push event my info fail ", zap.Error(err))
		return
	}

}
